package fox.framework.rpc.converter;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import fox.framework.rpc.common.StringUtils;
import fox.framework.rpc.server.dispatcher.router.DataBinder;

import java.lang.reflect.Type;

/**
 * @author cuichao
 * @Description: KryoConverter
 * @Date: create in 2021/1/31 21:22
 */
public class KryoConverter implements RpcMessageConverter {
    private final String name = "kryo";
    private final String mediaType = "kryo";
    private final int bufferSize = 4096;

    @Override
    public String getConverterName() {
        return name;
    }

    @Override
    public boolean hasSupport(String protocol,String mediaType) {
        return (!StringUtils.isEmpty(mediaType)) && mediaType.contains(this.mediaType) ;
    }


    @Override
    public <T> T decode(byte[] source, Class<T> cls) {
        Object object = readWithClass(source);
        if(object == null){
            return null;
        }
        return (T)object;
    }


    @Override
    public Object decode(byte[] source, Type type) {
        Object object = readWithClass(source);
        if(object == null){
            return null;
        }
        return object;
    }


    @Override
    public Object[] decode(byte[] source, DataBinder[] dataBinders) {
        Object object = readWithClass(source);
        if(object == null){
            return null;
        }
        return (Object[]) object;
    }

    @Override
    public byte[] encode(Object object) {
        Kryo kryo = KryoFactory.get();
        Output output = new Output(bufferSize);
        try {
            kryo.writeClassAndObject(output,object);
            byte[] bytes = output.toBytes();
            return bytes;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }finally {
            output.flush();
            output.close();
        }
    }

    private Object readWithClass(byte[] source){
        Kryo kryo = KryoFactory.get();
        Input input = new Input(source);
        try {
           return kryo.readClassAndObject(input);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }finally {
            input.close();
        }
    }

}
